package com.project.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.common.api.ApprovalApi;
import com.common.core.domain.AjaxResult;
import com.common.core.domain.entity.ProcessConfig;
import com.common.core.domain.entity.SysUser;
import com.common.core.service.ProcessConfigService;
import com.common.utils.CurrentRoleUtils;
import com.common.utils.SecurityUtils;
import com.common.utils.StringUtils;
import com.common.utils.bean.BizProcessMessages;
import com.common.utils.bean.ReflectionUtils;
import com.common.utils.uuid.IdUtils;
import com.flowable.domain.vo.FlowQueryVo;
import com.flowable.domain.vo.task.BpmTaskApproveReqVO;
import com.flowable.service.IFlowTaskService;
import com.project.domain.bo.MiddleCheckOrCompleteBo;
import com.common.utils.QueryWrapperUtils;
import com.project.domain.entity.BizProjectMiddleCheck;
import com.project.domain.vo.BizProjectMiddleCheckVo;
import com.project.domain.vo.NavigationForProVo;
import com.project.mapper.BizProjectMiddleCheckMapper;
import com.project.service.IBizProjectMiddleCheckService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.function.BiConsumer;
import java.util.function.Function;

@Service("biz_project_middle_check")
public class ProjectMiddleCheckServiceImpl extends ServiceImpl<BizProjectMiddleCheckMapper, BizProjectMiddleCheck> implements IBizProjectMiddleCheckService {
    @Autowired
    private BizProjectMiddleCheckMapper bizProjectMiddleCheckMapper;

    @Autowired
    ProjectInitServiceImpl projectInitService;


    //发起流程
    @Autowired
    private ApprovalApi approvalApi;

    //流程引擎
    @Autowired
    private IFlowTaskService flowTaskService;

    //流程配置
    @Autowired
    private ProcessConfigService processService;

    /**
     * 左上角根据状态的数量统计
     * @param bizProjectMiddleCheck
     * @return
     */
    public List<NavigationForProVo.NameAndCount> selectGroups(MiddleCheckOrCompleteBo bizProjectMiddleCheck){
        List<NavigationForProVo.NameAndCount> res = new ArrayList<>();
        try{
            QueryWrapper<NavigationForProVo.NameAndCount> queryWrapper = new QueryWrapper<>();
            queryWrapper = this.getConditions(queryWrapper,bizProjectMiddleCheck,"group");//拼条件

            QueryWrapperUtils.getParamsProBusiness(queryWrapper,SecurityUtils.getLoginUser().getUser());//用户权限
            res = bizProjectMiddleCheckMapper.selectGroups(queryWrapper,bizProjectMiddleCheck);
        }catch (Exception exception){
            res = null;
        }
        return res;
    }

    /**
     * 查询项目中检
     *
     * @param ID 项目中检主键
     * @return 项目中检
     */
    @Override
    public BizProjectMiddleCheck selectBizProjectMiddleCheckByID(String ID)
    {
        try{
            return bizProjectMiddleCheckMapper.selectDetail(ID);
        }catch (Exception exception){
            return new BizProjectMiddleCheck();
        }
//        return bizProjectMiddleCheckMapper.selectById(ID);
    }

    /**
     * 查询项目中检列表
     *
     * @param bizProjectMiddleCheck 项目中检
     * @param type
     * @return 项目中检
     */
    @Override
    public IPage<BizProjectMiddleCheckVo> selectBizProjectMiddleCheckList(MiddleCheckOrCompleteBo bizProjectMiddleCheck, String type)
    {
        IPage<BizProjectMiddleCheckVo> res = new Page<>();
        try{
            QueryWrapper<BizProjectMiddleCheckVo> queryWrapper = new QueryWrapper<>();
            queryWrapper = this.getConditions(queryWrapper,bizProjectMiddleCheck,"list");//拼条件

            QueryWrapperUtils.getParamsProBusiness(queryWrapper,SecurityUtils.getLoginUser().getUser());//用户权限
            //处理排序字段
            String orderStr = StringUtils.isNotBlank(bizProjectMiddleCheck.getOrderStr())?bizProjectMiddleCheck.getOrderStr():"createdate";
            String orderType = StringUtils.isNotBlank(bizProjectMiddleCheck.getOrderType())?bizProjectMiddleCheck.getOrderType():"desc";
            bizProjectMiddleCheck.setOrderStr(projectInitService.changeStringToUp(orderStr));
            bizProjectMiddleCheck.setOrderType(orderType);

            if(type.equals("select")){
                IPage<BizProjectMiddleCheckVo> myPage = new Page<>(bizProjectMiddleCheck.getPageNo(), bizProjectMiddleCheck.getPageSize());
                res = bizProjectMiddleCheckMapper.selectListInfos(myPage,queryWrapper,bizProjectMiddleCheck);
                res = this.getCheckInfosForList(res,"项目中检",BizProjectMiddleCheckVo::setTaskId,BizProjectMiddleCheckVo::setIsAuditor,BizProjectMiddleCheckVo::getProcessInstanceId);
            }else{
                IPage<BizProjectMiddleCheckVo> myPage = new Page<>(1, 1000);
                res = bizProjectMiddleCheckMapper.selectListInfosForExport(myPage,queryWrapper,bizProjectMiddleCheck);
            }
        }catch (Exception exception){
            String ex = exception.getMessage();
        }

        return res;
    }

    /**
     * 拼条件
     * @param queryWrapper
     * @param bizProjectMiddleCheck
     * @return
     */
    private QueryWrapper getConditions(QueryWrapper queryWrapper,MiddleCheckOrCompleteBo bizProjectMiddleCheck,String funcType){
        try{
            bizProjectMiddleCheck.setProjectTypeCode(addQuotationToStr(bizProjectMiddleCheck.getProjectTypeCode()));//处理项目分类id
            bizProjectMiddleCheck.setUnitId(addQuotationToStr(bizProjectMiddleCheck.getUnitId()));//处理所属单位id
            bizProjectMiddleCheck.setCheckstatus(addQuotationToStr(bizProjectMiddleCheck.getCheckstatus()));//处理审核状态id

            //处理中检日期字段（年份4、年月7、年月日）
            String startCheckTime = changeDateString(bizProjectMiddleCheck.getStartTime(),"start");
            String endCheckTime = changeDateString(bizProjectMiddleCheck.getEndTime(),"end");

            queryWrapper.eq(StringUtils.isNotBlank(bizProjectMiddleCheck.getProClass()), "zb.PROJECT_CLASS", bizProjectMiddleCheck.getProClass())
                    .eq(StringUtils.isNotBlank(bizProjectMiddleCheck.getProId()), "PROJECT_ID", bizProjectMiddleCheck.getProId())
                    .ge(StringUtils.isNotBlank(startCheckTime), "MIDDLE_CHECK_DATE", startCheckTime)
                    .le(StringUtils.isNotBlank(endCheckTime), "MIDDLE_CHECK_DATE", endCheckTime);
            if(funcType.equals("list")){
                queryWrapper.eq(StringUtils.isNotBlank(bizProjectMiddleCheck.getCheckstatusByGroup()), "zb.CHECKSTATUS", bizProjectMiddleCheck.getCheckstatusByGroup());
            }

            return queryWrapper;
        }catch (Exception exception){
            return queryWrapper;
        }
    }

    /**
     *
     * @param oldPage
     * @param moduleName
     * @param setTaskId
     * @param setIsAuditor
     * @param getProcessInstanceId
     * @param <T>
     */
    public <T> IPage<T> getCheckInfosForList(IPage<T> oldPage, String moduleName, BiConsumer<T,String> setTaskId,BiConsumer<T,Boolean> setIsAuditor,
                                                Function<T,String> getProcessInstanceId){
        try{
            List<T> oldList = oldPage.getRecords();
            if(oldList != null && oldList.size()>0){
                //获取当前用户所有的代办列表
                ProcessConfig processConfig = processService.getProcessByModelName(moduleName);
                FlowQueryVo queryVo = new FlowQueryVo();
                queryVo.setProcessDefinitionKey(processConfig.getProcessKey());
                // 获取流程任务列表,Map<instanceId, taskId>
                Map<String, String> instanceTaskMap = flowTaskService.todoListBydefKey_Api(queryVo);
                for(T obj:oldList){
                    String processInstanceId = getProcessInstanceId.apply(obj);//获取流程实例ID
                    if(StringUtils.isNotEmpty(processInstanceId) && instanceTaskMap.containsKey(processInstanceId)){
                        setTaskId.accept(obj,instanceTaskMap.get(processInstanceId));
                        setIsAuditor.accept(obj,true);
                    }else{
                        setIsAuditor.accept(obj,false);
                    }
                }

                oldPage.setRecords(oldList);
            }
        }catch (Exception exception){
            String ex = exception.getMessage();
        }

        return oldPage;
    }

    /**
     * 保存项目中检信息（审核逻辑处理）
     *
     * @param bizProjectMiddleCheck 项目中检
     * @param operateType 操作类型
     * @return 结果
     */
    @Override
    public AjaxResult saveBizProjectMiddleCheck(BizProjectMiddleCheck bizProjectMiddleCheck, String operateType)
    {
        String middelCheckId = "";
        Integer submitType = bizProjectMiddleCheck.getSubmitType() == null?-1:bizProjectMiddleCheck.getSubmitType();
        String processInstanceId = "";
        String currentRoleKey = CurrentRoleUtils.getCurrentRoleKey(); //当前角色
        String checkStatus = bizProjectMiddleCheck.getCheckstatus();
        switch (submitType){
            case -1:{
                //暂存：新建编辑都只保存信息，不做任何其他操作
                if(!currentRoleKey.equals("biz_kyms") && !currentRoleKey.equals("biz_kycgly") || !StringUtils.isNotBlank(checkStatus) ){
                    bizProjectMiddleCheck.setCheckstatus("-1");//科研管理员、秘书的暂存都不改状态
                }
                middelCheckId = this.saveMiddleCheckInfos(bizProjectMiddleCheck,operateType);
                return StringUtils.isNotBlank(middelCheckId)?middelCheckId.contains("失败")?AjaxResult.error(middelCheckId):AjaxResult.success(BizProcessMessages.SAVE_SUCCESS):AjaxResult.error(BizProcessMessages.SAVE_FAIL);
            }
            case 1:{
                //提交（科研人员）：新建编辑均保存信息+发起流程
                bizProjectMiddleCheck.setCheckstatus("1");
                bizProjectMiddleCheck = ReflectionUtils.updateFields(bizProjectMiddleCheck, BizProjectMiddleCheck.class);
                middelCheckId = this.saveMiddleCheckInfos(bizProjectMiddleCheck,operateType);
                if(StringUtils.isNotBlank(middelCheckId)){
                    if(middelCheckId.contains("失败")){
                        return AjaxResult.error(middelCheckId);
                    }else{
                        processInstanceId = approvalApi.businessEntryApproval(middelCheckId, "项目中检");//发起流程并返回示例id
                        //保存成功但流程实例id为空 -> 发起流程失败
                        return !StringUtils.isNotBlank(processInstanceId)?AjaxResult.warn(BizProcessMessages.SAVE_PARTIAL_SUCCESS):AjaxResult.success(BizProcessMessages.SAVE_SUCCESS);
                    }
                }else{
                    return AjaxResult.error(BizProcessMessages.SAVE_FAIL);
                }
            }
            case 2:{
                //保存并通过（管理员）：审核中且是当前审核人-》调流程接口；直接通过-》实例id为0
                if(operateType.equals("add") || operateType.equals("edit") && (!StringUtils.isNotBlank(checkStatus) || StringUtils.isNotBlank(checkStatus)&&!checkStatus.equals("1"))){
                    //新建时的保存并通过直接将实例id置为0
                    //审核状态是暂存*不通过 -》直接将实例id置为0
                    bizProjectMiddleCheck = ReflectionUtils.updateFields(bizProjectMiddleCheck, BizProjectMiddleCheck.class);
                    bizProjectMiddleCheck.setProcessInstanceId("0");
                    bizProjectMiddleCheck.setCheckstatus("2");
                    middelCheckId = this.saveMiddleCheckInfos(bizProjectMiddleCheck,operateType);
                    return StringUtils.isNotBlank(middelCheckId)?middelCheckId.contains("失败")?AjaxResult.error(middelCheckId):AjaxResult.success(BizProcessMessages.SAVE_SUCCESS):AjaxResult.error(BizProcessMessages.SAVE_FAIL);
                }else{
                    //审核状态为审核中且是当前审核人（审核人逻辑前端处理）：保存并调流程接口
                    try{
                        middelCheckId = this.saveMiddleCheckInfos(bizProjectMiddleCheck,operateType);
                        if(StringUtils.isNotBlank(middelCheckId)){
                            if(middelCheckId.contains("失败")){
                                return AjaxResult.error(middelCheckId);
                            }else{
                                BpmTaskApproveReqVO bta = new BpmTaskApproveReqVO();
                                bta.setId(bizProjectMiddleCheck.getTaskId());
                                bta.setReason(SecurityUtils.getNickName() + "保存并通过");
                                flowTaskService.approveTask(SecurityUtils.getUserId(), bta);
                                return AjaxResult.success(BizProcessMessages.SAVE_SUCCESS);
                            }
                        }else{
                            return AjaxResult.error(BizProcessMessages.SAVE_FAIL);
                        }
                    }catch (Exception exception){
                        return AjaxResult.warn(BizProcessMessages.SAVE_SUCCESS_APPROVE_FAIL);
                    }

                }
            }
            default: return AjaxResult.error(BizProcessMessages.SAVE_FAIL);
        }
    }

    /**
     * 保存中检信息（业务）
     * @param bizProjectMiddleCheck
     * @param operateType
     * @return
     */
    private String saveMiddleCheckInfos(BizProjectMiddleCheck bizProjectMiddleCheck,String operateType){
        String res = "";
        int operRes = 0;
        SysUser loginUser = SecurityUtils.getLoginUser().getUser();
        Date date = new Date();
        SimpleDateFormat dateFormat= new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

        try{
            //判断中检时间格式
            String middleCheckDate = bizProjectMiddleCheck.getMiddleCheckDate();
            if(StringUtils.isNotBlank(middleCheckDate)){
                if(isValidTimeFormat(bizProjectMiddleCheck.getMiddleCheckDate(),"yyyy-MM-dd") && isValidTimeFormat(bizProjectMiddleCheck.getMiddleCheckDate(),"yyyy-MM-dd  HH:mm:ss")){
                    return "保存失败，时间格式错误！";
                }else{
                    bizProjectMiddleCheck.setMiddleCheckDate(middleCheckDate + " 00:00:00");
                }
            }else{
                bizProjectMiddleCheck.setMiddleCheckDate(null);
            }

            bizProjectMiddleCheck.setLasteditdate(dateFormat.parse(dateFormat.format(date)));
            bizProjectMiddleCheck.setLasteditusername(loginUser.getNickName());
            bizProjectMiddleCheck.setLastedituserid(loginUser.getUserRealId());
            if(operateType.equals("add")){
                bizProjectMiddleCheck.setID(IdUtils.simpleUUID());
                bizProjectMiddleCheck.setCreatedate(dateFormat.parse(dateFormat.format(date)));
                bizProjectMiddleCheck.setCreateuserid(loginUser.getUserRealId());
                bizProjectMiddleCheck.setCreateusername(loginUser.getNickName());
                operRes = bizProjectMiddleCheckMapper.insert(bizProjectMiddleCheck);
            }else{
                operRes = bizProjectMiddleCheckMapper.updateById(bizProjectMiddleCheck);
            }

            if(operRes > 0){
                res = bizProjectMiddleCheck.getID();
            }
        }catch (Exception exception){
            String ex = exception.getMessage();
        }

        return res;
    }

    /**
     * 批量删除项目中检
     *
     * @param IDs 需要删除的项目中检主键
     * @return 结果
     */
    @Override
    public int deleteBizProjectMiddleCheckByIDs(String[] IDs)
    {
        return bizProjectMiddleCheckMapper.deleteBatchIds(Arrays.asList(IDs));
    }

    /**
     * 删除项目中检信息
     *
     * @param ID 项目中检主键
     * @return 结果
     */
    @Override
    public int deleteBizProjectMiddleCheckByID(String ID)
    {
        return bizProjectMiddleCheckMapper.deleteById(ID);
    }

    /**
     * 给字符串加引号
     * @param oldStr
     * @return
     */
    public String addQuotationToStr(String oldStr){
        if(StringUtils.isNotBlank(oldStr)){
            String newStr = oldStr.replace(",","','");
            return newStr ;
        }else{
            return oldStr;
        }
    }

    /**
     * 处理其他时间字符串
     * @param dateStr
     * @param startOrEnd
     * @return
     */
    public String changeDateString(String dateStr,String startOrEnd){
        if(StringUtils.isNotBlank(dateStr)){
            int strLength = dateStr.length();
            if(startOrEnd.equals("start")){
                if(strLength == 4){
                    dateStr = dateStr + "-01-01 00:00:00";
                }else if(strLength == 7){
                    dateStr = dateStr + "-01 00:00:00";
                }if(strLength == 10){
                    dateStr = dateStr + " 00:00:00";
                }
            }else{
                if(strLength == 4){
                    dateStr = dateStr + "-12-31 23:59:59";
                }else if(strLength == 7){
                    dateStr += "-01"; // 默认到每月的第一天
                    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
                    LocalDate date = LocalDate.parse(dateStr, formatter);
                    LocalDate lastDayOfMonth = date.withDayOfMonth(date.lengthOfMonth());
                    DateTimeFormatter outputFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
                    dateStr = lastDayOfMonth.format(outputFormatter) + " 23:59:59";
                }else if(strLength == 10){
                    dateStr = dateStr + " 23:59:59";
                }
            }
        }
        return dateStr;
    }

    public boolean isValidTimeFormat(String time, String format) {
        SimpleDateFormat sdf = new SimpleDateFormat(format);
        sdf.setLenient(false); // 设置为严格解析
        try {
            sdf.parse(time);
            return true; // 解析成功，格式有效
        } catch (ParseException e) {
            return false; // 解析失败，格式无效
        }
    }
}
